/**
 * Created by Meathill on 2017/7/8.
 */

const path = require('path');
const del = require('del');
const gulp = require('gulp');
const tap = require('gulp-tap');
const source = require('vinyl-source-stream');
const buffer = require('vinyl-buffer');
const handlebars = require('handlebars');
const es = require('event-stream');
const sequence = require('run-sequence');
const stylus = require('gulp-stylus');
const cleanCSS = require('gulp-clean-css');
const rename = require('gulp-rename');
const replace = require('gulp-replace');
const webpack = require('webpack');
const webpackStream = require('webpack-stream');
const uglify = require('gulp-uglify');
const imageMin = require('gulp-imagemin');
const cheerio = require('cheerio');
const htmlMin = require('gulp-htmlmin');
const gulpIf = require('gulp-if');

const DEST = 'build/';
const CDN = require('./cdn.json');

const configs = {};
const pages = {};
let template;
let isBuild = false;

handlebars.registerHelper('equal', (value, target, options) => {
  if (value === target) {
    return options.fn(this);
  } else {
    return options.inverse(this);
  }
});

gulp.task('page-config', () => {
  return gulp.src('pages/*.json')
    .pipe(tap( file => {
      configs[path.basename(file.path, '.json')] = JSON.parse(file.contents.toString());
    }));
});

gulp.task('template', () => {
  return gulp.src('template.hbs')
    .pipe(gulpIf(isBuild, replace(/node_modules\/([\w\-\.]+)\/((dist|build)\/)?/g, (match, repo) => {
      return CDN[repo];
    })))
    .pipe(tap( file => {
      template = handlebars.compile(file.contents.toString());
    }));
});

gulp.task('page-content', () => {
  return gulp.src(['*.dev.html'])
    .pipe(tap( file => {
      pages[path.basename(file.path, '.dev.html')] = file.contents.toString();
    }))
});

gulp.task('html', () => {
  let streams = Object.keys(pages).map( file => {
    let stream = source(`${file}.html`);
    let config = configs[file];
    config.content = pages[file];
    config.isBuild = isBuild;
    let html = template(config);
    if (isBuild) {
      let $ = cheerio.load(html, {
        decodeEntities: false
      });
      $('img:not(.no-lazy)')
        .after(function () {
          let img = $(this).clone();
          let noscript = cheerio.load('<noscript></noscript>');
          noscript('noscript').append(img);
          return noscript.html();
        })
        .attr('data-original', function () {
          return $(this).attr('src');
        })
        .attr('src', './img/spacer.svg')
        .addClass('lazy');
      $('img.no-lazy').removeClass('no-lazy');
      html = $.html();
    }

    stream.write(html);

    process.nextTick( () => {
      stream.end();
    });

    return stream
      .pipe(buffer())
      .pipe(gulpIf(isBuild, htmlMin({
        collapseWhitespace: true,
        removeComments: true,
        removeEmptyAttributes: true
      })))
      .pipe(gulp.dest(isBuild ? DEST : './'));
  });

  return es.merge(streams);
});

gulp.task('clear', () => {
  return del(DEST);
});

gulp.task('stylus', () => {
  return gulp.src('styl/screen.styl')
    .pipe(stylus({
      'include css': true
    }))
    .pipe(cleanCSS({
      level: 2
    }))
    .pipe(rename('screen.min.css'))
    .pipe(gulp.dest(DEST + 'css/'));
});

gulp.task('webpack', () => {
  gulp.src('app/main.js')
    .pipe(webpackStream(require('./webpack.config.prod'), webpack))
    .pipe(uglify())
    .pipe(rename('main.min.js'))
    .pipe(gulp.dest(DEST + 'js/'));
});

gulp.task('build', callback => {
  isBuild = true;
  callback();
});

gulp.task('image', () => {
  return gulp.src('./assets/img/**')
    .pipe(imageMin())
    .pipe(gulp.dest('./img/'));
});

gulp.task('copy', () => {
  return gulp.src('./img/**')
    .pipe(gulp.dest(DEST + 'img/'));
});

gulp.task('prepare', taskDone => {
  sequence(
    ['page-config', 'page-content', 'template'],
    taskDone
  );
});

gulp.task('watch', ['prepare'], () => {
  gulp.watch('./template.hbs', () => {
    return sequence(
      'template',
      'html'
    );
  });

  gulp.watch('./*.dev.html', () => {
    return sequence(
      'page-content',
      'html'
    );
  });

  gulp.watch('./pages/*.json', () => {
    return sequence(
      'page-config',
      'html'
    );
  });

  sequence('html');
});

gulp.task('default', taskDone => {
  sequence(
    'clear',
    'build',
    ['page-config', 'page-content', 'template'],
    ['html', 'stylus', 'webpack', 'copy'],
    taskDone
  );
});